package railRoad.db;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import railRoad.Route;
import railRoad.Schedule;
import railRoad.Station;
import railRoad.dao.PassangerDAO;
import railRoad.dao.RouteDAO;
import railRoad.dao.StationDAO;
import railRoad.dao.TicketDAO;
import railRoad.dao.UserDAO;
import railRoad.dao.interfaces.IDAO;
import railRoad.exception.DBException;

/**
 * Implementation of database routine for H2
 * 
 * @see DBReader
 * @author Rukin
 * 
 */
public class H2Reader extends DBReader {

	/**
	 * Read all DB context to classes
	 */
	@Override
	public void read() throws SQLException {
		readRoute();
	}

	private void readStation(Route route) throws SQLException {
		Connection connection = getConnection();
		Statement statement = connection.createStatement();

		ResultSet resultSet = statement
				.executeQuery("SELECT * FROM STATION WHERE ROUTE_ID = "
						+ route.getRoute_id());
		while (resultSet.next()) {
			route.addStation(new Station(resultSet.getInt("station_id"),
					resultSet.getString("name"),
					resultSet.getFloat("altitude"), resultSet
							.getFloat("longitude")));
		}

		close(connection);
	}

	private void readRoute() throws SQLException {
		Connection connection = getConnection();
		Statement statement = connection.createStatement();

		ResultSet resultSet = statement.executeQuery("SELECT * FROM ROUTE");
		Route route = null;
		while (resultSet.next()) {
			route = new Route(resultSet.getInt("route_id"),
					resultSet.getInt("available_tickets"));

			readStation(route);
			Schedule.getInstance().addRoute(route);
		}

		close(connection);
	}

	/**
	 * Write all class context to DB
	 */
	@Override
	public void write() throws SQLException {

		Connection connection = getConnection();
		connection.setAutoCommit(false);

		writeRoute();

		int routeCount = Schedule.getInstance().size();
		Route route = null;

		for (int i = 0; i < routeCount; i++) {
			route = Schedule.getInstance().getRouteAt(i);

			writeStation(route);
		}

		connection.commit();

		close(connection);

	}

	private void writeRoute() throws SQLException {
		Connection connection = getConnection();
		PreparedStatement preparedStatement = connection
				.prepareStatement("INSERT INTO ROUTE(ROUTE_ID, AVAILABLE_TICKETS ) VALUES (?,?);");

		int routeCount = Schedule.getInstance().size();
		Route route = null;

		for (int i = 0; i < routeCount; i++) {
			route = Schedule.getInstance().getRouteAt(i);

			preparedStatement.setInt(1, route.getRoute_id());
			preparedStatement.setInt(2, route.getAvailableTicket());
			preparedStatement.addBatch();
		}

		preparedStatement.executeBatch();

		close(connection);
	}

	private void writeStation(Route route) throws SQLException {
		Connection connection = getConnection();
		PreparedStatement preparedStatement = connection
				.prepareStatement("INSERT INTO STATION( ROUTE_ID , NAME , ALTITUDE , LONGITUDE ) VALUES (?,?,?,?)");

		int stationCount = route.size();
		Station station = null;

		for (int i = 0; i < stationCount; i++) {
			station = route.getStationAt(i);
			preparedStatement.setInt(1, route.getRoute_id());
			preparedStatement.setString(2, station.getStationName());
			preparedStatement.setFloat(3, station.getAltitude());
			preparedStatement.setFloat(4, station.getLongitude());

			preparedStatement.addBatch();
		}

		preparedStatement.executeBatch();

		close(connection);
	}

	@Override
	public <T> void insert(T object, int parrentId) throws DBException {
		IDAO<T> dao = createDao(object);
		if (dao != null) {
			try {
				dao.insert(object, parrentId);
			} catch (DBException e) {
				throw new DBException(e.getMessage());
			}
		}// if
	}// insert

	@Override
	public <T> void update(T object) throws DBException {
		IDAO<T> dao = createDao(object);
		if (dao != null) {
			try {
				dao.update(object);
			} catch (DBException e) {
				throw new DBException(e.getMessage());
			}
		}// if
	}

	@Override
	public <T> T select(T object, int id) throws DBException {
		IDAO<T> dao = createDao(object);

		T obj = null;

		if (dao != null) {
			try {
				obj = dao.select(id);
			} catch (DBException e) {
				throw new DBException(e.getMessage());
			}
		}// if

		return obj;
	}// select int

	@Override
	public <T> T select(T object, String field) throws DBException {
		IDAO<T> dao = createDao(object);

		T obj = null;

		if (dao != null) {
			try {
				obj = dao.select(field);
			} catch (DBException e) {
				throw new DBException(e.getMessage());
			}
		}// if

		return obj;
	}// select String

	@Override
	public <T> void delete(T object) throws DBException {
		IDAO<T> dao = createDao(object);
		if (dao != null) {
			try {
				dao.delete(object);
			} catch (DBException e) {
				throw new DBException(e.getMessage());
			}
		}// if
	}// delete

	private <T> IDAO<T> createDao(T object) {
		String name = object.getClass().getName();

		IDAO<?> dao = null;

		if (name.equals("railRoad.Station"))
			dao = new StationDAO();
		else if (name.equals("railRoad.Route"))
			dao = new RouteDAO();
		else if (name.equals("railRoad.User"))
			dao = new UserDAO();
		else if (name.equals("railRoad.Passenger"))
			dao = new PassangerDAO();
		else if (name.equals("railRoad.Ticket"))
			dao = new TicketDAO();

		return (IDAO<T>) dao;
	}
}// class H2Reader
